/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package com.playground.core.service.impl;

import com.playground.core.entity.GameTitle;
import com.playground.core.entity.LoggedPlayer;
import com.playground.core.entity.PlayerStatus;
import com.playground.core.entity.Queue;
import com.playground.core.entity.Room;
import com.playground.core.entity.RoomStatus;
import com.playground.core.repository.QueueRepository;
import com.playground.core.repository.RoomRepository;
import com.playground.core.service.QueueService;
import com.playground.core.service.RoomService;
import java.util.Date;
import java.util.Iterator;
import java.util.List;
import java.util.Observable;
import javax.inject.Inject;
import org.springframework.stereotype.Service;

/**
 *
 * @author Tiago Peres
 */
@Service("queueService")
public class QueueServiceImpl extends Observable implements QueueService {
    @Inject
    private QueueRepository queueRepository;
    
    @Inject
    private RoomRepository roomRepository;
    
    @Inject
    private RoomService roomService;

    public Room addToQueue(List<LoggedPlayer> players, GameTitle gameTitle) {
        Queue q = queueRepository.getQueueByGameTitle(gameTitle);
        Room hostingRoom = null;
        
        if (null == q){
            q = new Queue(gameTitle);
            q = queueRepository.save(q);
        }
        
        Iterator<Room> rooms = q.getRooms().iterator();
        while (rooms.hasNext() && null == hostingRoom){
            Room r = rooms.next();
            List<LoggedPlayer> playersInRoom = r.getPlayers();
            if(r.getStatus().equals(RoomStatus.opened) && playersInRoom.size() + players.size() <= r.getMaxPlayers()){
                playersInRoom.addAll(players);
                hostingRoom = r;
            }
        }
        
        // If no room was found, a new one is created
        if (null == hostingRoom){
            hostingRoom = roomService.setUpNewRoom(gameTitle);
            hostingRoom.getPlayers().addAll(players);
            q.push(hostingRoom);
        }
        
        // alter the players status to inQueue and set the room in each one of them
        for (LoggedPlayer lp : players){
            lp.setStatus(PlayerStatus.inQueue);
            lp.setRoom(hostingRoom);
        }
        
        // if the room got full
        if (hostingRoom.getPlayers().size() == hostingRoom.getMaxPlayers()){
            hostingRoom.setStatus(RoomStatus.full);
            // updates the index of RoomStatus
            roomRepository.save(hostingRoom);
            q.getRooms().remove(hostingRoom);
            System.out.println("NOTIFYING " + countObservers()  + " OBSERVERS...");
            setChanged();
            notifyObservers(hostingRoom);
        }
        
        return hostingRoom;
    }

    public boolean confirmGame(LoggedPlayer player, Room room) {
        if (null != roomRepository.findOne(room.getId()) && room.getStatus().equals(RoomStatus.waitingForPlayersConfirmation)){
            player.setStatus(PlayerStatus.ready);
            Iterator<LoggedPlayer> players = room.getPlayers().iterator();
            boolean allConfirmed = true;
            while (players.hasNext() && allConfirmed){
                LoggedPlayer lp = players.next();
                if (!lp.getStatus().equals(PlayerStatus.ready)){
                    allConfirmed = false;
                }
            }
            if (allConfirmed){
                room.setStatus(RoomStatus.ready);
                roomRepository.save(room);
                setChanged();
                notifyObservers(room);
            }
            return true;
        }
        return false;
    }

    public boolean removePlayerFromQueue(LoggedPlayer player, Room room) {
        throw new UnsupportedOperationException("Not supported yet."); //To change body of generated methods, choose Tools | Templates.
    }

    public boolean requeueRoom(Room room) {
        if (room.getStatus().equals(RoomStatus.refused)){
            room.setStatus(RoomStatus.opened);
            roomRepository.save(room);
            queueRepository.getQueueByGameTitle(room.getGameTitle()).addAsFirst(room);
            return true;
        }
        return false;
    }

    public boolean waitForPlayersConfirmation(Room room) {
        if (!room.getStatus().equals(RoomStatus.full) || null == roomRepository.findOne(room.getId())){
            return false;
        }
        room.setStatus(RoomStatus.waitingForPlayersConfirmation);
        room.setWaitingForPlayersConfirmationSince(new Date());
        roomRepository.save(room);
        return true;
    }

    public boolean startGame(Room room) {
        if (room.getStatus().equals(RoomStatus.ready)){
            room.setStatus(RoomStatus.running);
            roomRepository.save(room);
            return true;
        }
        return false;
    }
    
}
